import {EventEmitter} from '../../base/events'
import {bus} from '@beshell/events-ts/bus'
import { conn } from '@beshell/conn-ts/Connection'
import { Protocol, Cmd } from '@beshell/conn-ts/Protocol'
import {AppModel} from '../AppModel'
let eventBus
import { PartBase } from "../parts/PartBase"
import { Stud } from "../Stud"
import { Usage } from "../StudUsage"
import CablePort from "./CablePort"

export abstract class Cable extends EventEmitter {

    protected mapHostStuds: {[key:string]: Stud|undefined} = {}
    protected mapDefaultHostStuds: {[key:string]: Stud|undefined} = {}

    public protocol = new Protocol

    constructor(public type:string, public title: string, public name: String, public baudrate: number) {
        super()

        // this.on('data.received', (data: number[])=>{

        //     this.protocol.receive(data, (cmd: Cmd, id: number, data: number[]) =>{
                
        //         this.emit("package.received", cmd, id, data, this)

        //         // 主动通知线路上的所有零件（不需要零件监听线路）
        //         // this.allParts((part: PartBase)=>{
        //         //     part.emit("package.received", cmd, id, data, this)
        //         // })
        //     })
        // })
    }
    setHostStud (usage: Usage, stud?: Stud) {
        // var oristud = this.mapHostStuds[usage]
        // if( oristud ) {
        //     oristud.serial = undefined
        // }
        if(stud){

            // if(stud.serial) {
            //     stud.serial.setHostStud(usage, undefined)
            // }

            // stud.serial = this
            stud.usage = usage
        }
        this.mapHostStuds[usage] = stud
        // console.log("cable", this)

        this.emit("cable.set.stud", this, usage, stud)
    }
    hostStud (usage: Usage) {
        return this.mapHostStuds[usage]
    }
    defaultHostStud (usage: Usage) {
        return this.mapDefaultHostStuds[usage]
    }

    isValid(): boolean {
        for(var u in this.mapHostStuds) {
            if(!this.mapHostStuds) {
                return false
            }
        }
        return true
    }
    
    async setup() {
        if(conn.isConnected || !conn.active) {
            return
        }
        let code = this.generateSetupCode()
        if(code) {
            await conn.active.write(code)
            await delay(1)
        }
    }

    // 返回/遍历 线缆连接（所有bus）的所有零件
    allParts(callback: (part:PartBase)=>void): PartBase[] {
        let items: PartBase[] = []
        for(let studName in this.mapHostStuds) {
            let bus = this.mapHostStuds[studName]?.bus
            if(bus){
                bus.allParts((part:PartBase, stud:Stud)=>{
                    if(items.includes(part)) {
                        return
                    }
                    items.push(part)
                    if(callback) {
                        callback(part)
                    }
                })
            }
        }
        return items
    }

    readPackage(cmd:Cmd|null=null, timeout=1000): Promise<number[]|null> {
        return new Promise(resolve=>{
            let _cb = (_cmd:Cmd, pkgId:number, data:number[])=>{
                if(cmd!=null && cmd!=_cmd) {
                    return
                }
                ;(data as any).id = pkgId
                this.off("package.received", _cb)
                clearTimeout(timer)
                resolve(data)
            }
            this.on("package.received", _cb)
            let timer = setTimeout(()=>{
                this.off("package.received", _cb)
                resolve(null)
            },timeout)
        })
    }

    sendPackage(cmd: Cmd, data: number[]|undefined=undefined, pkgId=-1) {
        let pkg = Protocol.pack(cmd, data, pkgId)
        this.write(pkg)
    }
    
    write(data: number[]): void {
        if(!conn.isConnected||!conn.active)
            return
        let code = `${this.name}.write([${data.join(',')}])\n`
        conn.active.write(code)
    }

    serialize() {
        let json: any = {
            studs: {}
        }
        for(let name in this.mapHostStuds) {
            if(this.mapHostStuds[name]) {
                json.studs[name] = this.mapHostStuds[name]?.info.name
            }
        }
        if( Object.keys(json.studs).length ) 
            return json
        else
            return null
    }

    unserialize(json: any, part: PartBase) {
        if(json.studs) {
            for(let name in json.studs) {
                let stud = part.findStudFromName(json.studs[name])
                if(!stud) {
                    console.error("unknow stud name: ", json.studs[name])
                    continue
                }
                this.setHostStud(name as Usage, stud)
            }
        }
    }

    public isFree() {
        return ! Object.values(this.mapHostStuds).length
    }

    public generateSetupCode(indent=0, freeFirst=false){
        return ''
    }

    public isOnline(device: CablePort) {
        if(this.constructor != device.cableClass) {
            return false
        }
        for(let usage in device.mapStuds) {
            let devStud = device.mapStuds[usage]
            if( !devStud.bus ) {
                continue
            }
            let provider
            try{
                provider = devStud.bus.findHostStud()
            } catch(e) {
                console.error(e)
            }
            if(!provider) {
                return false
            }
            if( provider != (this as any).mapHostStuds[usage] ) {
                return false
            }
        }
        return true
    }
}